package examples.computations;

import java.util.ArrayList;

import org.apache.commons.functor.UnaryFunction;

import util.*;
import util.functors.AccociBinaryOP;
import util.functors.BinaryOperator;

public class TagMatch extends DiffComputation<Tag, MarkedTags, Bool> {
	private final static String CLOSED = ")";
	private final static String OPENED = "(";

	public TagMatch() {

		init = new MarkedTags(new ArrayList<String>(), 0, 0);

		oplus = new AccociBinaryOP<Bool>() {

			@Override
			public Bool evaluate(Bool left, Bool right) {
				return new Bool(right.get() && left.get());
			}

			@Override
			public Bool id() {
				return new Bool(true);
			}

		};

		otimes = new AccociBinaryOP<MarkedTags>() {
			@Override
			public MarkedTags evaluate(MarkedTags l, MarkedTags r) {

				ArrayList<String> tmp = new ArrayList<String>();

				if (l.get2nd().get() <= r.get3rd().get()) {
					tmp.addAll(l.get().fst.get());
					return new MarkedTags(new TextList(tmp), new Int(l.get2nd()
							.get()), new Int(r.get3rd().get()
							+ l.get3rd().get() - l.get2nd().get()));
				}

				else {
					// ArrayList<String> tmp = new ArrayList<String>();
					if (r.get1st() != null && r.get1st().get() != null
							&& !r.get1st().get().isEmpty())
						tmp.addAll(r.get1st().get());

					tmp.addAll((int)r.get3rd().get(), l.get1st().get());
					// TextList list = new TextList(tmp);

					return new MarkedTags(tmp, l.get2nd().get()
							+ r.get2nd().get() - r.get3rd().get(), l.get3rd()
							.get());
				}
			}

			@Override
			public MarkedTags id() {
				return new MarkedTags(new ArrayList<String>(), 0, 0);
			}
		};

		g = new UnaryFunction<MarkedTags, Bool>() {
			@Override
			public Bool evaluate(MarkedTags obj) {
				// obj.get() == null ||
			//	return new Bool(obj.get2nd().get() == 0);
				return new Bool(obj.get1st().get() == null || obj.get1st().get().isEmpty());
			}
		};

		p = new BinaryOperator<Tag, MarkedTags, Bool>() {

			@Override
			public Bool evaluate(Tag x, MarkedTags cs) {
				// ArrayList<Int> val = new ArrayList<Int>();
				if (OPENED.equalsIgnoreCase(x.get())) {
					return new Bool(true);
				} else if (CLOSED.equalsIgnoreCase(x.get())) {
					// val.add(x);
					return new Bool(cs.get2nd().get() > 0
							&& ("(".equalsIgnoreCase(x.get()) && cs.get()
									.getFst().get().get(0).equals(")")));
				} else
					return new Bool(true);
			}

			@Override
			public Tag getInstanceOfT0() {
				return new Tag("A");
			}

		};

		q = new UnaryFunction<Tag, MarkedTags>() {
			@Override
			public MarkedTags evaluate(Tag da) {
				if (OPENED.equalsIgnoreCase(da.get())) {
					ArrayList<String> xs = new ArrayList<String>();
					xs.add(da.toString());
					//TextList lst = new TextList(xs);
					return new MarkedTags(xs, 1, 0);
				} else if (CLOSED.equalsIgnoreCase(da.get())) {

					return new MarkedTags(new ArrayList<String>(), 0, 1);
				} else
					return new MarkedTags(new ArrayList<String>(), 0, 0);
			}

		};

	}

}
